<?php
/**
 * 基础通信类
 * 
 * @author virowin<virowin@gmail.com>
 * @version $1.0
 */
class Lib_APIClient {
	/**
	 * http call only GET method
	 * <code>
	 * $Lib_APIClient = new Lib_APIClient();
	 * $result3 = $Lib_APIClient::httpCall($name,$parameters);
	 * </code>
	 * @param string $name url
	 * @param array $arguments GET arguments
	 * @param string $type ('xml','array','json')
	 * @return array
	 */
    public static function httpCall($name, $arguments, $type="xml",$post_params=array()) {
    	if (!in_array($type,array('xml','serl','json','string','array','xml_obj','geturl'))) {
        	$type = 'xml';
        }

		if (is_array($arguments)) {
			$s = http_build_query($arguments);	//do rawurlencode here
		}else{
			$s = $arguments;	//针对某些不能urlencode传过去的参数 直接外面拼装参数... 
		}
        $request_url = $name . "?$s";
        
        if ($type=='geturl') {	//仅仅获得url,不进行获取和解析
        	return $request_url;
        }
        
        //file_get_contents
//		$opts = array('http' => array('method' => 'GET', 'timeout' => 5));
//		$result = file_get_contents($request_url, FALSE, stream_context_create($opts));
        
        //curl
        $curl_result = self::curl_one_fetch($request_url,$post_params);
        $result = $curl_result['result'];
		
        if (isset($_REQUEST['api_debug'])) {
			echo "<pre>url::";
			var_dump($request_url);
			var_dump($arguments);
			var_dump($post_params);
			$url_info = parse_url($request_url);
			var_dump(gethostbynamel($url_info['host']));
			var_dump($result);
			echo "</pre>";
        }
        if (0 == strlen($result)) {
        	Lib_Logger::log_api($request_url,'GET error');
            return array();
        }

        $result = trim($result);	//必不可少...
        if ($type == "xml") {
			$result = Lib_XMLUtil::xml_to_array($result);
			return $result;
        }elseif ($type =='serl'){
        	return unserialize($result);
        }elseif ($type=='json'){
        	return object_2_array(json_decode($result));
        }elseif ($type=='string'){
        	return $result;
        }elseif ($type=='xml_obj'){
        	$xml_string = convert_xml_encode( $result );
        	$obj = simplexml_load_string( $xml_string, 'SimpleXMLElement', LIBXML_NOCDATA );
        	return $obj;
        }
        return array();
    }
    
    public static function curl_one_fetch($request_url,$post_params){
    	$ch = curl_init();
		curl_setopt( $ch, CURLOPT_HEADER, 0 );
		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); //Set curl to return the data instead of printing it to the browser.
		curl_setopt( $ch, CURLOPT_URL, $request_url );
		curl_setopt($ch, CURLOPT_TIMEOUT, 5);
		if (is_array($post_params) && count($post_params)) {
			curl_setopt( $ch, CURLOPT_POST, 1 );
			curl_setopt( $ch, CURLOPT_POSTFIELDS, http_build_query($post_params));  
		}
		$result = curl_exec( $ch );
		$info = curl_getinfo( $ch );
		curl_close( $ch );
		return array('result'=>$result,'info'=>$info);
    }

    public static function curl_upload($url, $data){
        $ch = curl_init() ;
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1) ;
        curl_setopt($ch, CURLOPT_URL, $url) ;
        curl_setopt($ch, CURLOPT_POST, 1) ;
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data) ;
        $rs = curl_exec($ch) ;
        $info = curl_getinfo($ch) ;
        if(!$rs){
            $rs = curl_error($ch) ;
        }
        curl_close($ch) ;
        return array('result'=>$rs, 'info'=>$info) ;
    }
    
	public static function curl_multi_fetch($urlarr=array()){
	    $result=$res=$ch=array();
	    $nch = 0;
	    $mh = curl_multi_init();
	    foreach ($urlarr as $nk => $url) {
	        $timeout=5;
	        $ch[$nch] = curl_init();
	        curl_setopt_array($ch[$nch], array(
	        CURLOPT_URL => $url,
	        CURLOPT_HEADER => false,
	        CURLOPT_RETURNTRANSFER => true,
	        CURLOPT_TIMEOUT => $timeout,
	        ));
	        curl_multi_add_handle($mh, $ch[$nch]);
	        ++$nch;
	    }
	    /* wait for performing request */
	    do {
	        $mrc = curl_multi_exec($mh, $running);
	    } while (CURLM_CALL_MULTI_PERFORM == $mrc);
	 
	    while ($running && $mrc == CURLM_OK) {
	        // wait for network
	        if (curl_multi_select($mh, 0.5) > -1) {
	            // pull in new data;
	            do {
	                $mrc = curl_multi_exec($mh, $running);
	            } while (CURLM_CALL_MULTI_PERFORM == $mrc);
	        }
	    }
	    if ($mrc != CURLM_OK) {
	        error_log("CURL Data Error");
	    }
	    /* get data */
	    $nch = 0;
	    foreach ($urlarr as $moudle=>$node) {
	        if (($err = curl_error($ch[$nch])) == '') {
	            $res[$nch]=curl_multi_getcontent($ch[$nch]);
	            $result[$moudle]=$res[$nch];
	        }
	        else
	        {
	            error_log("curl error");
	        }
	        curl_multi_remove_handle($mh,$ch[$nch]);
	        curl_close($ch[$nch]);
	        ++$nch;
	    }
	    curl_multi_close($mh);
	    return  $result;
	}
    /**
     * soap call
     * @param string $wsUrl
     * @param string $func
     * @param string $arr
     * @return array
     */
    public function soapCall($wsUrl, $func, $arr, $xmlname='', $resultname='') {
        if($xmlname){
            $xml = self::changeArray2Xml($arr);
            $param[$xmlname] = $xml;
        }else
            $param = $arr;
        try {
            $soapObject = new SoapClient($wsUrl);
            $out = $soapObject->__soapCall($func, array($param));
            if (!$resultname) {
            	$resultname = $func.'Result';
            }
            $data = $out->{$resultname};
            
            if (isset($_REQUEST['api_debug'])) {
            	echo "<pre>wsurl::";
				var_dump($wsUrl);
				$url_info = parse_url($wsUrl);
				var_dump(gethostbynamel($url_info['host']));
				var_dump($param);
				var_dump($func);
				var_dump($out);
				var_dump($data);
				echo "</pre>";
//				exit;
            }
            
			return $data;
        } catch (SoapFault $fault) {
        	if (isset($_REQUEST['api_debug'])) {
	        	echo "<pre>";
	        	var_dump($wsUrl);
	        	$url_info = parse_url($wsUrl);
				var_dump(gethostbynamel($url_info['host']));
				var_dump($param);
				var_dump($func);
	        	var_dump($fault);
	        	echo "</pre>";
        	}
        	$str = "SOAP Fault!code:".$fault->faultcode."  string:".$fault->faultstring;
        	Lib_Logger::log_api( $wsUrl, $str );
            return array();
        }
    }

    /*
     * function changeArray2Xml
     * 将array转换为.net webservice xml参数
     * @input array
     * @output string
     */
    private static function changeArray2Xml($arr) {
        $xml = '<?xml version="1.0" encoding="gbk" standalone="yes" ?>';
        $xml .= '<inputObject>';
        $xml_list = '';
        $flag = false;
        foreach ($arr as $key => $value) {
            $type = gettype($value);
            if ($type == "array") {
                $flag = true;
                $xml_list .= '<row>';
                foreach ($value as $vkey => $v) {
                    $xml_list .= self::makeXmlBody($vkey, $v);
                }
                $xml_list .= '</row>';
            } else {
                $xml_list .= self::makeXmlBody($key, $value);
            }
        }
        if ($flag)
            $xml_list = '<dbvalue>' . $xml_list . '</dbvalue>';
        $xml .=$xml_list . '</inputObject>';
        return $xml;
    }

    /*
     * function makeXmlBody
     * 通过输入的键值生成xml代码
     * @input: mix $key,mix $value
     * @output: string
     */
    private static function makeXmlBody($key, $value) {
        $xmlbody = '<' . $key . '>';
        if (is_numeric($value) || trim($value) == '' || $value == null) {
            $xmlbody .= $value;
        } else {
            $xmlbody .= '<![CDATA[' . $value . ']]>';
        }
        $xmlbody .= '</' . $key . '>';
        return $xmlbody;
    }

}

?>
